classdef AbstractSignal < handle
    %ABSTRACTSIGNAL Summary of this class goes here
    %   Detailed explanation goes here
    
    properties
        name
        zi_server
        subscribed_signal
    end
    
    methods
        function obj = AbstractSignal(name)
            %ABSTRACTSIGNAL Construct an instance of this class
            %   Detailed explanation goes here
            getSession;
            
            obj.name = name;
            obj.zi_server = sess.getZIServer;
            obj.subscribed_signal = {};
        end
    end
    %%
    methods
        function obj = subscribe_signal(obj, signal, node, varargin)
            p=inputParser;
            p.addRequired('signal', @(x) isa(x,  'MeasurementComponent.Signal.Signal'));
            p.addRequired('node', @(x) isa(x, 'ziStreamSignal'));
            p.addOptional('group', [1, 1, 1], @(x) isnumeric(x) && length(x) == 3 && x(3)<=x(1)*x(2));
            p.parse(signal, node, varargin{:});
            
            liaChannel = signal.getLIAchannel();
            switch node.type
                case 'Demod'
                    eval(sprintf('subscribe_node = ziDemod%d.%s;', Miscellaneous.ziIndexNum(liaChannel.index), node.signal));
                case 'PID'
                    eval(sprintf('subscribe_node = ziPID%d.%s;', Miscellaneous.ziIndexNum(liaChannel.index), node.signal));
            end
            obj.subscribed_signal = [obj.subscribed_signal; {liaChannel.device.device, subscribe_node, p.Results.group}];
        end
        function obj = unsubscribe_signal(obj)
            obj.subscribed_signal = {};
        end
        function res = getDemodSignal(obj, totalduration, varargin)
            zs = obj.zi_server;
            %
            p=inputParser; p.PartialMatching = false;
            p.addRequired('totalduration',  @(x) x>0);
            p.addParameter('name',          'PLOTTER',             @ischar);
            p.addParameter('rate',          100,                   @(x) x>0);
            p.addParameter('burstduration', 0.2,                   @(x) x>0);
            p.addParameter('mode',          ziEnumGridMode.Linear, @ziEnumGridMode.test);
            p.addParameter('average',    1,       @(x) x>0);
            % corresopond to 'trig_device'
            p.addParameter('trig_dev',     '',                           @(x) isa(x, 'EquipmentControl.ZI.ziMFLI') || isempty(x)); 
            p.addParameter('trig_node',    [],                           @(x) isa(x, 'ziStreamNode') || isempty(x));
            p.addParameter('edge',         ziEnumTrigEdgeSlope.Positive, @ziEnumTrigEdgeSlope.test);
            p.addParameter('level',        0.0,                          @isnumeric);
            p.addParameter('hysteresis',   0.0,                          @isnumeric);
            p.addParameter('count',        1,                            @(x) x>0);
            p.addParameter('bits',         1,                            @(x) isa(x, 'int64') );
            p.addParameter('bitmask',      1,                            @(x) isa(x, 'int64') );
            p.addParameter('holdofftime',  0.0,                          @(x) x>=0.0 );
            p.addParameter('holdoffcount', 0,                            @(x) x>=0 );
            p.addParameter('delay',       -0.1,                          @isnumeric );
            p.addParameter('update_mode',       'append',               @(x) ismember(x, {'append', 'replace'}));
            p.parse(totalduration, varargin{:});
            %
            if ~isempty(p.Results.trig_dev)
                trig_devName = p.Results.trig_dev.device;
            else
                trig_devName = '';
            end
            
            %
            zs.unsubscribe_DemodSignal();
            for k=1:size(obj.subscribed_signal, 1)
                zs.subscribe_DemodSignal(obj.subscribed_signal{k, :});
            end
            res = zs.viewDemodSignal(totalduration, varargin{:}, 'trig_device', trig_devName);
        end
        
        function res = getDemodSpectrum(obj, nCol, varargin)
            zs = obj.zi_server;
            %
            p=inputParser; p.PartialMatching = false;
            p.addRequired('nCol',  @(x) x > 2 );            
            p.addParameter('name',         'Spectrum',                   @ischar);
            p.addParameter('mode',         ziEnumGridMode.Linear,        @ziEnumGridMode.test);
            p.addParameter('fSpan',        1e3,                          @(x) x>0);
            p.addParameter('average',      1,                            @(x) x>0);
            p.addParameter('fft_window',  ziEnumFFTWindow.Hann,   @ziEnumFFTWindow.test);
            % corresopond to 'trig_device'
            p.addParameter('trig_dev',     '',                           @(x) isa(x, 'EquipmentControl.ZI.ziMFLI') || isempty(x)); 
            p.addParameter('trig_node',    [],                           @(x) isa(x, 'ziStreamNode') || isempty(x));
            p.addParameter('edge',         ziEnumTrigEdgeSlope.Positive, @ziEnumTrigEdgeSlope.test);
            p.addParameter('level',        0.0,                          @isnumeric);
            p.addParameter('hysteresis',   0.0,                          @isnumeric);
            p.addParameter('count',        1,                            @(x) x>0);
            p.addParameter('bits',         1,                            @(x) isa(x, 'int64') );
            p.addParameter('bitmask',      1,                            @(x) isa(x, 'int64') );
            p.addParameter('holdofftime',  0.0,                          @(x) x>=0.0 );
            p.addParameter('holdoffcount', 0,                            @(x) x>=0 );
            p.addParameter('delay',       -0.1,                          @isnumeric );
            p.parse(nCol, varargin{:});
            %
            if ~isempty(p.Results.trig_dev)
                trig_devName = p.Results.trig_dev.device;
            else
                trig_devName = '';
            end
            
            %
            zs.unsubscribe_DemodSignal();
            for k=1:size(obj.subscribed_signal, 1)
                zs.subscribe_DemodSignal(obj.subscribed_signal{k, :});
            end
            res = zs.viewDemodSpectrum(nCol, varargin{:}, 'trig_device', trig_devName);
        end
        
        function res = getParameterDependence(obj, device, node, start, stop, varargin)
            zs = obj.zi_server;
            p=inputParser;
            % sweep control
            p.addRequired('device', @(x) isa(x, 'EquipmentControl.ZI.ziMFLI'));
            p.addRequired('node', @(x) isa(x, 'ziSweepNode'));
            p.addRequired('start', @isnumeric);
            p.addRequired('stop', @isnumeric);
            p.addParameter('npoint', 100, @(x) x>0);
            p.addParameter('sweep_mode', 0, @ziEnumSweepMode.test);
            p.addParameter('isLog', false, @islogical);
            % sweep filter
            p.addParameter('bandwidthcontrol', ziEnumSweepBWMode.Mannual, @ziEnumSweepBWMode.test);
            p.addParameter('order', 4, @(x) ismember(x, 1:8));     % fixed & auto mode
            p.addParameter('bandwidth', 100, @(x) x>0);            % fixed mode
            p.addParameter('maxbandwidth', 1.25e6, @(x) x>0);      % auto mode, Maximal bandwidth used in auto bandwidth mode in [Hz]. The default is 1.25MHz.
            p.addParameter('bandwidthoverlap', false, @islogical); % auto mode, Sets the bandwidth overlap mode (default 0).  0 = Disable; 1 = Enable
            p.addParameter('omegasuppression', 40, @(x) x>0);      % auto mode  Damping in [dB] of omega and 2omega components. Default is 40dB in favor of sweep speed. Use higher value for strong offset values or 3omega measurement methods.
            % sweep settling
            p.addParameter('settling_time', 0);            % double  Settling time before measurement is performed, in [s]
            p.addParameter('settling_tc', 0);              % double  Settling precision: 5 ~ low precision; 15 ~ medium precision; 50 ~ high precision
            p.addParameter('settling_inaccuracy', 10e-3);  % double     [1e-13, 0.1]
            % sweep averaging
            p.addParameter('averaging_tc', 0);     % double  Min averaging time [tc]: 0 = no averaging (see also time!); 5 ~ low precision; 15 ~ medium precision; 50 ~ high precision;
            p.addParameter('averaging_sample', 0); % int     Min samples to average: 1 = no averaging (if averaging/tc = 0);
            p.addParameter('averaging_time', 0);   % double  Min averaging time [s]
            % sweep options
            p.addParameter('phaseunwrap', 0); % bool    Enable unwrapping of slowly changing phase evolutions around the +/-180 degree boundary.
            p.addParameter('sincfilter', 0);  % bool    Enables the sinc filter if the sweep frequency s below 50 Hz. This will improve the sweep speed at low frequencies as omega components do not need to be suppressed by the normal low pass filter.
            p.addParameter('awgcontrol', 0);  % bool    Enable AWG control for sweeper. If enabled the sweeper will automatically start the AWG and records the sweep sample based on the even index in hwtrigger.
            
            p.addParameter('name',     'SWEEPER', @ischar);
            p.parse(device, node, start, stop, varargin{:});
            %
            zs.unsubscribe_DemodSignal();
            for k=1:size(obj.subscribed_signal, 1)
                zs.subscribe_DemodSignal(obj.subscribed_signal{k, :});
            end
            res = zs.viewParamDependance(device.device, node, start, stop, varargin{:});
        end
    end
end

